package chapter01;


import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.Stack;

class Action{
    int from;
    int to;
    int water;
    public Action(int from,int to,int water){
        this.from=from;
        this.to=to;
        this.water=water;
    }
    @Override
    public String toString(){
        return "Action{["+(from+1)+","+(to+1)+","+water+"]}";
    }
}
class Bucket{
    int capacity;
    public Bucket(int capacity){
        this.capacity=capacity;

    }
}
class State{
    int[] s;
    public State(int... a){
        s=a;
    }
    public State(State state){
        s= Arrays.copyOf(state.s,state.s.length);
    }
    public boolean equals(Object o){
        if(this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;
        State state = (State) o;
        return Arrays.equals(s,state.s);
    }
    public int hashCode(){
        return  Arrays.hashCode(s);

    }
    public String toString(){
        return "State{"+ Arrays.toString(s)+"}";
    }

}


public class SplitWater {
    Set<State> states= new HashSet<>();
    Stack<State> order=new Stack<>();
    Stack<Action> actions =new Stack<>();
    int count =0;
    Bucket[] buckets={new Bucket(8),new Bucket(5),new Bucket(3)};
    public void search(final State state){
        if(isFinalState(state)){
            count++;
            printAction();
            printOrder();
            return;
        }
        order.push(state);
        states.add(state);
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                Action action = newAction(i,j,state);
                if(action==null)
                    continue;
                final State newState= getNewState(state,action);
                if(hasSearched(newState))
                    continue;
                actions.push(action);
                search((newState));
                actions.pop();
            }
        }
        states.remove(state);
        order.pop();

    }

    private boolean hasSearched(State state) {
        return states.contains(state);
    }


    private void printAction() {
        for (int i = 0; i < actions.size(); i++) {
            System.out.println(actions.elementAt(i));
        }
        System.out.println("----------------------");
    }
    private void printOrder() {
        for (int i = 0; i < order.size(); i++) {
            System.out.println(order.elementAt(i));
        }
        System.out.println(new State(4,4,0));
        System.out.println("****************");
    }



    private boolean isFinalState(State state) {
        return state.s[0]==4 && state.s[1]==4&&state.s[2]==0;
    }
    private Action newAction(int i,int j,State state){
        if(i==j || state.s[i]==0 || state.s[j]>=buckets[j].capacity)
            return null;
        int water=0;
        if(state.s[i]>buckets[j].capacity-state.s[j]){
            water=buckets[j].capacity-state.s[j];

        }
        else {
            water=state.s[i];

        }
        return new Action(i,j,water);

    }
    private State getNewState(State state, Action action) {
    State newState= new State(state);
    newState.s[action.from]-= action.water;
    newState.s[action.to] += action.water;
    return newState;
    }

    public static void main(String[] args) {
        SplitWater splitWater =new SplitWater();
        State initState=new State(8,0,0);
        splitWater.search(initState);
        System.out.println(splitWater.count);
    }
}
